-----------------------------------------------------------------------
-- File:        Blocks.adb
-- Description: Provides an interface to the hardware control of blocks,
--		    calls procedures that set the Cab and polarity of a block,
--              that init blocks and flip the polarity of a block. It also
--              provides block acquiring and release functionality
--
-- Requires:    Io_Ports,Unsigned_Types,Raildefs,Dio192defs, Dda06defs,
--              Int32defs,Dio192_Blocks
--				
-- Author:     Maria Mitrevska
-----------------------------------------------------------------------
with Ada.Text_IO;--*
with Io_Ports;
with Unsigned_Types;
use Unsigned_Types;  -- 1.8
with Raildefs,
   Dio192defs, Dda06defs, Int32defs;
use Raildefs;
with Dio192_Blocks;

package body Blocks is --PROTECTED

   --Declare types
   type Block_Reg_Array is array (Raildefs.Block_Idx range 0 .. 11) of Dio192defs.Block_Register;
   type Block_State is array (Raildefs.Block_Idx range 0 .. 24) of Boolean;
   type Block_Owner is array (Raildefs.Block_Idx range 0 .. 24) of Train_Idx;
   type MaxTime is array (Raildefs.Block_Id) of Natural;
   Max_Time : constant Natural := 50;


   --Protected Object Declaration
   protected Object is

      --Declarations of protected procedures
      procedure Acquire_Block (
            Success :    out Boolean;
            Train   : in     Raildefs. Train_Id;
            B       : in     Raildefs. Block_Idx);

      procedure Release_Block (
            Success :    out Boolean;
            Train   : in     Raildefs. Train_Id;
            B       : in     Raildefs. Block_Idx);


      procedure Set_Block (
            Success :    out Boolean;
            Train   : in     Raildefs. Train_Id;
            B       : in     Raildefs.Block_Id;
            Cab     : in     Raildefs.Cab_Type;
            Pol     : in     Raildefs.Polarity_Type);

      procedure Reverse_Block (
            Success :    out Boolean;
            Train   : in     Raildefs. Train_Id;
            B       : in     Raildefs.Block_Id);
   private
      --private variables
      Block_Status:Block_State:= (others => False);
      Owner: Block_Owner:= (others => 0);
      Timeout : MaxTime := (others => Max_Time);

   end Object;

   --Protected Object Body
   protected body Object is

      --Acquire a Block
      procedure Acquire_Block (
            Success :    out Boolean;
            Train   : in     Raildefs. Train_Id;
            B       : in     Raildefs. Block_Idx) is
      begin
         if Timeout(B) = 0 or Block_Status(B)=False or Owner(B) = Train then
            Success := True;
            Block_Status(B):=True;
            Owner(B):=Train;
            Timeout(B) := Max_Time;
         else
            Timeout(B) :=  Timeout(B) -1;
            Success := False;
         end if;
         Ada.Text_Io.Put_Line("Acquiring Block...."&B'Img&"Enquiring   "&Train'Img&"Owner..."&Owner(B)'Img&"Success "&Success'Img); --*
      end Acquire_Block;

      --Release a Block
      procedure Release_Block (
            Success :    out Boolean;
            Train   : in     Raildefs. Train_Id;
            B       : in     Raildefs. Block_Idx) is
      begin
         if(Train =Owner(B)) then
            Block_Status(B):=False;
            Owner(B):=0;
            Success := True;
         else
            Success := False;
         end if;
         Ada.Text_Io.Put_Line("Release Block...."&B'Img&"Owner..."&Owner(B)'Img); --*
      end Release_Block;

      --Set Cab and Polarity of a Block
      procedure Set_Block (
            Success :    out Boolean;
            Train   : in     Raildefs. Train_Id;
            B       : in     Raildefs.Block_Id;
            Cab     : in     Raildefs.Cab_Type;
            Pol     : in     Raildefs.Polarity_Type) is
      begin
         if(Train =Owner(B)) then
            Dio192_Blocks.Set_Cab(B, Cab);
            Dio192_Blocks.Set_Polarity(B, Pol);
            Success := True;
         else
            Success := False;
         end if;
         Ada.Text_Io.Put_Line("Set Block...."&B'Img&"Owner..."&Owner(B)'Img); --*
      end Set_Block;


      --Reverse the polarity of a Block
      procedure Reverse_Block (
            Success :    out Boolean;
            Train   : in     Raildefs. Train_Id;
            B       : in     Raildefs.Block_Id) is

      begin
         if(Train =Owner(B)) then
            Dio192_Blocks.Flip_Block(B);
            Success := True;
         else
            Success := False;
         end if;
      end Reverse_Block;

   end Object;

   --Public Procedures

   --Init Blocks
   procedure Init_Block is
   begin
      Dio192_Blocks.Init_Blocks;
   end Init_Block;

   --Acquire a Block
   procedure Acquire_Block (
         Success :    out Boolean;
         Train   : in     Raildefs. Train_Id;
         B       : in     Raildefs. Block_Idx) is

   begin

      Object. Acquire_Block (Success, Train, B);

   end Acquire_Block;

   --Release a Block
   procedure Release_Block (
         Success :    out Boolean;
         Train   : in     Raildefs. Train_Id;
         B       : in     Raildefs. Block_Idx) is

   begin
      Object. Release_Block (Success,Train,B);
   end Release_Block;


   --Set Cab and Polarity of a Block
   procedure Set_Block (
         Success :    out Boolean;
         Train   : in     Raildefs. Train_Id;
         B       : in     Raildefs.Block_Id;
         Cab     : in     Raildefs.Cab_Type;
         Pol     : in     Raildefs.Polarity_Type) is
   begin
      Object.Set_Block (Success,Train,B,Cab,Pol);
   end Set_Block;

   --Reverse the polarity of a Block
   procedure Reverse_Block (
         Success :    out Boolean;
         Train   : in     Raildefs. Train_Id;
         B       : in     Raildefs.Block_Id) is
   begin
      Object.Reverse_Block(Success,Train,B);
   end Reverse_Block;
end Blocks;